home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
program
/
srcbkvt.zip
/
ASC.ZIP
/
RR796.ASC
< prev
Wrap
Text File
|
1996-07-08
|
16KB
|
387 lines
_Rambling In Real Time_
by Michael Abrash
Listing One
// Part of Win32 program to demonstrate z-sorted spans. Whitespace removed for
// space. Full source code available at ftp.idsoftware.com/mikeab/ddjzsort.zip.
#define MAX_SPANS 10000
#define MAX_SURFS 1000
#define MAX_EDGES 5000
typedef struct surf_s {
struct surf_s *pnext, *pprev;
int color, visxstart, state;
double zinv00, zinvstepx, zinvstepy;
} surf_t;
typedef struct edge_s {
int x, xstep, leading;
surf_t *psurf;
struct edge_s *pnext, *pprev, *pnextremove;
} edge_t;
// Span, edge, and surface lists
span_t spans[MAX_SPANS];
edge_t edges[MAX_EDGES];
surf_t surfs[MAX_SURFS];
// Bucket list of new edges to add on each scan line
edge_t newedges[MAX_SCREEN_HEIGHT];
// Bucket list of edges to remove on each scan line
edge_t *removeedges[MAX_SCREEN_HEIGHT];
// Head and tail for the active edge list
edge_t edgehead, edgetail;
// Edge used as sentinel of new edge lists
edge_t maxedge = {0x7FFFFFFF};
// Head/tail/sentinel/background surface of active surface stack
surf_t surfstack;
// pointers to next available surface and edge
surf_t *pavailsurf;
edge_t *pavailedge;
// Returns true if polygon faces the viewpoint, assuming a clockwise
// winding of vertices as seen from the front.
int PolyFacesViewer(polygon_t *ppoly, plane_t *pplane)
{
int i;
point_t viewvec;
for (i=0 ; i<3 ; i++)
viewvec.v[i] = ppoly->verts[0].v[i] - currentpos.v[i];
// Use an epsilon here so we don't get polygons tilted so
// sharply that the gradients are unusable or invalid
if (DotProduct (&viewvec, &pplane->normal) < -0.01)
return 1;
return 0;
}
// Add the polygon's edges to the global edge table.
void AddPolygonEdges (plane_t *plane, polygon2D_t *screenpoly)
{
double distinv, deltax, deltay, slope;
int i, nextvert, numverts, temp, topy, bottomy, height;
edge_t *pedge;
numverts = screenpoly->numverts;
// Clamp the polygon's vertices just in case some very near
// points have wandered out of range due to floating-point imprecision
for (i=0 ; i<numverts ; i++) {
if (screenpoly->verts[i].x < -0.5)
screenpoly->verts[i].x = -0.5;
if (screenpoly->verts[i].x > ((double)DIBWidth - 0.5))
screenpoly->verts[i].x = (double)DIBWidth - 0.5;
if (screenpoly->verts[i].y < -0.5)
screenpoly->verts[i].y = -0.5;
if (screenpoly->verts[i].y > ((double)DIBHeight - 0.5))
screenpoly->verts[i].y = (double)DIBHeight - 0.5;
}
// Add each edge in turn
for (i=0 ; i<numverts ; i++) {
nextvert = i + 1;
if (nextvert >= numverts)
nextvert = 0;
topy = (int)ceil(screenpoly->verts[i].y);
bottomy = (int)ceil(screenpoly->verts[nextvert].y);
height = bottomy - topy;
if (height == 0)
continue; // doesn't cross any scan lines
if (height < 0) {
// Leading edge
temp = topy;
topy = bottomy;
bottomy = temp;
pavailedge->leading = 1;
deltax = screenpoly->verts[i].x -
screenpoly->verts[nextvert].x;
deltay = screenpoly->verts[i].y -
screenpoly->verts[nextvert].y;
slope = deltax / deltay;
// Edge coordinates are in 16.16 fixed point
pavailedge->xstep = (int)(slope * (float)0x10000);
pavailedge->x = (int)((screenpoly->verts[nextvert].x +
((float)topy - screenpoly->verts[nextvert].y) *
slope) * (float)0x10000);
} else {
// Trailing edge
pavailedge->leading = 0;
deltax = screenpoly->verts[nextvert].x -
screenpoly->verts[i].x;
deltay = screenpoly->verts[nextvert].y -
screenpoly->verts[i].y;
slope = deltax / deltay;
// Edge coordinates are in 16.16 fixed point
pavailedge->xstep = (int)(slope * (float)0x10000);
pavailedge->x = (int)((screenpoly->verts[i].x +
((float)topy - screenpoly->verts[i].y) * slope) *
(float)0x10000);
}
// Put the edge on the list to be added on top scan
pedge = &newedges[topy];
while (pedge->pnext->x < pavailedge->x)
pedge = pedge->pnext;
pavailedge->pnext = pedge->pnext;
pedge->pnext = pavailedge;
// Put the edge on the list to be removed after final scan
pavailedge->pnextremove = removeedges[bottomy - 1];
removeedges[bottomy - 1] = pavailedge;
// Associate the edge with the surface we'll create for this polygon
pavailedge->psurf = pavailsurf;
// Make sure we don't overflow the edge array
if (pavailedge < &edges[MAX_EDGES])
pavailedge++;
}
// Create the surface, so we'll know how to sort and draw from the edges
pavailsurf->state = 0;
pavailsurf->color = currentcolor;
// Set up the 1/z gradients from the polygon, calculating the base value at
// screen coordinate 0,0 so we can use screen coordinates directly when
// calculating 1/z from the gradients
distinv = 1.0 / plane->distance;
pavailsurf->zinvstepx = plane->normal.v[0] * distinv *
maxscreenscaleinv * (fieldofview / 2.0);
pavailsurf->zinvstepy = -plane->normal.v[1] * distinv *
maxscreenscaleinv * (fieldofview / 2.0);
pavailsurf->zinv00 = plane->normal.v[2] * distinv -
xcenter * pavailsurf->zinvstepx -
ycenter * pavailsurf->zinvstepy;
// Make sure we don't overflow the surface array
if (pavailsurf < &surfs[MAX_SURFS])
pavailsurf++;
}
// Scan all the edges in the global edge table into spans.
void ScanEdges (void)
{
int x, y;
double fx, fy, zinv, zinv2;
edge_t *pedge, *pedge2, *ptemp;
span_t *pspan;
surf_t *psurf, *psurf2;
pspan = spans;
// Set up the active edge list as initially empty, containing
// only the sentinels (which are also the background fill). Most
// of these fields could be set up just once at start-up
edgehead.pnext = &edgetail;
edgehead.pprev = NULL;
edgehead.x = -0xFFFF; // left edge of screen
edgehead.leading = 1;
edgehead.psurf = &surfstack;
edgetail.pnext = NULL; // mark edge of list
edgetail.pprev = &edgehead;
edgetail.x = DIBWidth << 16; // right edge of screen
edgetail.leading = 0;
edgetail.psurf = &surfstack;
// Background surface is the entire stack initially, and is infinitely far
// away, so everything sorts in front of it. Could be set once at start-up
surfstack.pnext = surfstack.pprev = &surfstack;
surfstack.color = 0;
surfstack.zinv00 = -999999.0;
surfstack.zinvstepx = surfstack.zinvstepy = 0.0;
for (y=0 ; y<DIBHeight ; y++) {
fy = (double)y;
// Sort in any edges that start on this scan
pedge = newedges[y].pnext;
pedge2 = &edgehead;
while (pedge != &maxedge) {
while (pedge->x > pedge2->pnext->x)
pedge2 = pedge2->pnext;
ptemp = pedge->pnext;
pedge->pnext = pedge2->pnext;
pedge->pprev = pedge2;
pedge2->pnext->pprev = pedge;
pedge2->pnext = pedge;
pedge2 = pedge;
pedge = ptemp;
}
// Scan out the active edges into spans. Start out with left background
// edge already inserted, and surface stack containing only background
surfstack.state = 1;
surfstack.visxstart = 0;
for (pedge=edgehead.pnext ; pedge ; pedge=pedge->pnext) {
psurf = pedge->psurf;
if (pedge->leading) {
// It's a leading edge. Figure out where it is relative to the